This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
MCPProxy is a Go-based desktop application that acts as a smart proxy for AI agents using the Model Context Protocol (MCP). It provides intelligent tool discovery, massive token savings, and built-in security quarantine against malicious MCP servers.
Current Architecture (Next Branch):
- Core Server (
mcpproxy): Headless HTTP API server with MCP proxy functionality - Tray Application (
mcpproxy-tray): Standalone GUI application that manages the core server
Key Benefits:
- Auto-start: Tray automatically starts core server if not running
- Port conflict resolution: Built-in detection and handling
- Independent operation: Core can run without tray (headless mode)
- Real-time sync: Tray updates via SSE connection to core API
# Build for current platform
go build -o mcpproxy ./cmd/mcpproxy
# Cross-platform build script (builds for multiple architectures)
./scripts/build.sh
# Quick local build
scripts/build.sh
#Build frontend and backend
make build# Generate all icon files (PNG for macOS/Linux, ICO for Windows)
# Requires: inkscape, imagemagick (convert), python3 with Pillow
./scripts/logo-convert.sh
# Generate Windows ICO file only (requires Python 3 with Pillow)
python3 scripts/create-ico.py
# Install Pillow if needed
pip install --break-system-packages Pillow
# or
python3 -m pip install --break-system-packages PillowNote: The Windows tray icon uses .ico format for better compatibility with the Windows system tray. The macOS/Linux versions use .png format. If you modify the logo, regenerate all icon files using the script above.
# Build Windows installer (requires Windows environment)
# Prerequisites: Inno Setup 6+ or WiX Toolset 4.x
# Using Inno Setup (recommended - single multi-arch installer):
# Install Inno Setup via Chocolatey
choco install innosetup -y
# Build installer for specific architecture
.\scripts\build-windows-installer.ps1 -Version "v1.0.0" -Arch "amd64"
.\scripts\build-windows-installer.ps1 -Version "v1.0.0" -Arch "arm64"
# Using WiX Toolset 4.x (alternative - MSI format):
# Install WiX as .NET global tool
dotnet tool install --global wix
# Build MSI installer
wix build -arch x64 -d Version=1.0.0.0 -d BinPath=dist\windows-amd64 wix\Package.wxs
# Output: dist\mcpproxy-setup-{version}-{arch}.exe (Inno Setup)
# or: dist\mcpproxy-{version}-windows-{arch}.msi (WiX)Note: Windows installers automatically configure system PATH, create Start Menu shortcuts, and support in-place upgrades. Inno Setup produces a single multi-architecture installer, while WiX generates separate MSI files per architecture. Both support silent installation (/VERYSILENT for Inno Setup, /qn for WiX MSI).
mainbranch: Stable releasesnextbranch: Prerelease builds with latest features- macOS DMG installers are signed and notarized
See docs/prerelease-builds.md for download instructions and workflow details.
IMPORTANT: Always run tests before committing changes!
# Quick API E2E test (required before commits)
./scripts/test-api-e2e.sh
# Verify OpenAPI endpoint coverage (required before commits if you modified REST endpoints)
./scripts/verify-oas-coverage.sh
# Full test suite (recommended before major commits)
./scripts/run-all-tests.sh
# Run unit tests
go test ./internal/... -v
# Run unit tests with race detection
go test -race ./internal/... -v
# Run original E2E tests (internal mocks)
./scripts/run-e2e-tests.sh
# Run binary E2E tests (with built mcpproxy)
go test ./internal/server -run TestBinary -v
# Run MCP protocol E2E tests
go test ./internal/server -run TestMCP -v
# Run specific test package
go test ./internal/server -v
# Run tests with coverage
go test -coverprofile=coverage.out ./internal/...
go tool cover -html=coverage.out
# Run OAuth E2E test suite
./scripts/run-oauth-e2e.sh
# Run OAuth test server unit tests
go test ./tests/oauthserver/... -v
# Run OAuth integration tests (starts test OAuth server)
OAUTH_INTEGRATION_TESTS=1 go test ./tests/oauthserver/... -run TestIntegration -vThe E2E tests use @modelcontextprotocol/server-everything which provides:
- Echo tools for testing basic functionality
- Math operations for complex calculations
- String manipulation for text processing
- File operations (sandboxed)
- Error simulation for error handling tests
Prerequisites for E2E tests:
- Node.js and npm installed (for everything server)
jqinstalled for JSON parsing- Built mcpproxy binary:
go build -o mcpproxy ./cmd/mcpproxy
Test failure investigation:
- Check
/tmp/mcpproxy_e2e.logfor server logs - Verify everything server is connecting: look for "Everything server is connected!"
- Ensure no port conflicts on 8081
# Run linter (requires golangci-lint v1.59.1+)
./scripts/run-linter.sh
# Or directly
golangci-lint run ./...MCPProxy provides CLI commands for managing upstream servers and monitoring health:
mcpproxy upstream list # List all servers
mcpproxy upstream logs <name> # View logs (--tail, --follow)
mcpproxy upstream restart <name> # Restart server (supports --all)
mcpproxy doctor # Run health checksCommon workflow:
mcpproxy doctor # Check overall health
mcpproxy upstream list # Identify issues
mcpproxy upstream logs failing-srv # View logs
mcpproxy upstream restart failing-srvSee docs/cli-management-commands.md for complete reference.
CLI commands automatically detect and use Unix socket/named pipe communication when the daemon is running:
Commands with socket support:
upstream list/logs/enable/disable/restart- Daemon connection with standalone fallbackdoctor- Requires daemon (shows live diagnostics)call tool- Daemon connection with standalone fallbackcode exec- Daemon connection with standalone fallbacktools list- Daemon connection with standalone fallback (NEW)auth login- Daemon connection with standalone fallback (NEW)auth status- Requires daemon (shows live OAuth state) (NEW)
Benefits of socket mode:
- Reuses daemon's existing server connections (faster)
- Shows real daemon state (not config file state)
- Coordinates OAuth tokens with running daemon
- No redundant server connection overhead
Standalone commands (no socket support needed):
secrets- Direct OS keyring operationstrust-cert- File system operationssearch-servers- Registry API operations
See docs/socket-communication.md for socket implementation details.
MCPProxy is split into two separate applications:
- Core Server (
mcpproxy): Headless API server - Tray Application (
mcpproxy-tray): GUI management interface
# Build both applications
CGO_ENABLED=0 go build -o mcpproxy ./cmd/mcpproxy # Core server
GOOS=darwin CGO_ENABLED=1 go build -o mcpproxy-tray ./cmd/mcpproxy-tray # Tray app
# Start core server (required) - binds to localhost by default for security
./mcpproxy serve
# Start core server on all interfaces (CAUTION: Network exposure)
./mcpproxy serve --listen :8080
# Start with custom API key
./mcpproxy serve --api-key="your-secret-key"
# Start tray application (optional, connects to core via API with auto-generated API key)
./mcpproxy-tray
# Custom configuration
./mcpproxy serve --config=/path/to/config.json
# Debug mode with trace logging
./mcpproxy serve --log-level=debug
# Debug specific server tools
./mcpproxy tools list --server=github-server --log-level=trace- Auto-starts core server if not running
- Port conflict resolution built-in
- Real-time updates via Server-Sent Events (SSE) over socket/pipe connection
- Cross-platform system tray integration
- Server management via GUI menus
The tray application uses a robust state machine architecture for reliable core management:
State Machine States:
StateInitializing→StateLaunchingCore→StateWaitingForCore→StateConnectingAPI→StateConnected- Error states:
StateCoreErrorPortConflict,StateCoreErrorDBLocked,StateCoreErrorGeneral,StateCoreErrorConfig - Recovery states:
StateReconnecting,StateFailed,StateShuttingDown
Key Components:
- Process Monitor (
cmd/mcpproxy-tray/internal/monitor/process.go): Monitors core subprocess lifecycle - Health Monitor (
cmd/mcpproxy-tray/internal/monitor/health.go): Performs socket-aware HTTP health checks on core API (/healthz,/readyz) - State Machine (
cmd/mcpproxy-tray/internal/state/machine.go): Manages state transitions and automatic retry logic
Error Classification: Core process exit codes are mapped to specific state machine events:
- Exit code 2 (port conflict) →
EventPortConflict - Exit code 3 (database locked) →
EventDBLocked - Exit code 4 (config error) →
EventConfigError - Exit code 5 (permission error) →
EventPermissionError - Other errors →
EventGeneralError
Automatic Retry Logic: Error states automatically retry core launch with exponential backoff:
StateCoreErrorGeneral: 2 retries with 3s delay (3 total attempts)StateCoreErrorPortConflict: 2 retries with 10s delayStateCoreErrorDBLocked: 3 retries with 5s delay- After max retries exceeded → transitions to
StateFailed - Retry count and attempts logged for transparency
Development Environment Variables:
MCPPROXY_TRAY_SKIP_CORE=1- Skip core launch (for development)MCPPROXY_CORE_URL=http://localhost:8085- Custom core URLMCPPROXY_TRAY_PORT=8090- Custom tray port
-
cmd/mcpproxy/- Main CLI application entry pointmain.go- Cobra CLI setup and command routingtools_cmd.go- Tools debugging commandscall_cmd.go- Tool execution commandstray_gui.go/tray_stub.go- System tray interface (build-tagged)
-
internal/runtime/- Core runtime lifecycle management (Phase 1-3 refactoring)runtime.go- Non-HTTP lifecycle, configuration, and state managementevent_bus.go- Event system for real-time updates and SSE integrationlifecycle.go- Background initialization, connection management, and tool indexingevents.go- Event type definitions and payload structures
-
internal/server/- HTTP server and MCP proxy implementationserver.go- HTTP server management and delegation to runtimemcp.go- MCP protocol implementation and tool routing
-
internal/httpapi/- REST API endpoints with chi routerserver.go-/api/v1endpoints, SSE events, and server controls
-
internal/upstream/- Modular client architecture (3-layer design)core/- Basic MCP client (stateless, transport-agnostic)managed/- Production client (state management, retry logic)cli/- Debug client (enhanced logging, single operations)
-
internal/config/- Configuration managementconfig.go- Configuration structures and validationloader.go- File loading and environment variable handling
-
internal/index/- Full-text search using Bleve- BM25 search index for tool discovery
- Automatic tool indexing and updates
-
internal/storage/- BBolt database for persistence- Tool statistics and metadata
- Server configurations and quarantine status
-
internal/cache/- Response caching layer -
cmd/mcpproxy-tray/- Standalone system tray application (separate binary)main.go- Core process launcher with state machine integrationinternal/state/- State machine for core lifecycle managementinternal/monitor/- Process and health monitoring systemsinternal/api/- Enhanced API client with exponential backoff
-
internal/logs/- Structured logging with per-server log files -
internal/management/- Centralized management service layerservice.go- Business logic for server lifecycle operations- Shared by CLI, REST API, and MCP protocol interfaces
- Configuration gates, event emission, and bulk operations
The management service (internal/management/) provides a centralized business logic layer for upstream server management operations, eliminating code duplication across CLI, REST API, and MCP interfaces.
Architecture Diagram:
┌─────────────────────────────────────────────────────────────┐
│ Client Interfaces │
├───────────────┬─────────────────┬───────────────────────────┤
│ CLI Commands │ REST API │ MCP Protocol │
│ (upstream) │ (/api/v1/*) │ (upstream_servers tool) │
└───────┬───────┴────────┬────────┴───────────┬───────────────┘
│ │ │
└────────────────┼────────────────────┘
│
▼
┌─────────────────────┐
│ Management Service │
│ (internal/mgmt/) │
└──────────┬──────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Runtime │ │ Config │ │ Events │
│Operations│ │ Gates │ │ Emitter │
└──────────┘ └──────────┘ └──────────┘
Key Components:
-
Service Interface (
service.go:16-102): Defines all management operations- Single-server:
RestartServer(),EnableServer(),DisableServer() - Bulk operations:
RestartAll(),EnableAll(),DisableAll() - Diagnostics:
GetServerHealth(),RunDiagnostics() - Server CRUD:
AddServer(),RemoveServer(),QuarantineServer() - Tool operations:
GetServerTools(),TriggerOAuthLogin()(added in spec 005)
- Single-server:
-
Configuration Gates: All operations respect centralized configuration guards
disable_management: Blocks all write operations when trueread_only_mode: Blocks all configuration modifications
-
Bulk Operations (
service.go:243-388): Efficient multi-server management- Sequential execution with partial failure handling
- Returns
BulkOperationResultwith success/failure counts - Collects per-server errors in results map
- Continues on individual failures, reports aggregate results
-
Event Integration: All operations emit events through event bus
servers.changed: Notifies UI of server state changes- Triggers SSE updates to web UI and tray application
- Enables real-time synchronization across interfaces
Benefits:
- Code Deduplication: 40%+ reduction in duplicate code across interfaces
- Consistent Behavior: All interfaces use identical business logic
- Centralized Validation: Configuration gates enforced in one place
- Easier Testing: Unit tests cover all interfaces through service layer
- Future Extensibility: New interfaces can reuse existing service methods
Usage Examples:
// CLI usage (cmd/mcpproxy/upstream_cmd.go:547-636)
result, err := client.RestartAll(ctx)
fmt.Printf(" Total servers: %d\n", result.Total)
fmt.Printf(" ✅ Successful: %d\n", result.Successful)
fmt.Printf(" ❌ Failed: %d\n", result.Failed)
// REST API usage (internal/httpapi/server.go:772-866)
mgmtSvc := s.controller.GetManagementService().(ManagementService)
result, err := mgmtSvc.RestartAll(r.Context())
s.writeSuccess(w, result)
// MCP protocol usage (future integration)
result, err := mgmtService.RestartAll(ctx)
return mcpResponse(result)OpenAPI Documentation: All REST endpoints are documented with OpenAPI 3.1 annotations and auto-generated Swagger spec. See oas/swagger.yaml for complete API reference.
MCPProxy uses platform-specific local IPC for secure communication between tray and core:
- Platform-Specific: Unix sockets (macOS/Linux), Named pipes (Windows)
- Zero Configuration: Auto-detects socket path from data directory
- Socket connections: Trusted by default (skip API key validation)
- TCP connections: Require API key authentication
File Locations:
- macOS/Linux:
~/.mcpproxy/mcpproxy.sock - Windows:
\\.\pipe\mcpproxy-<username>
Disable socket (use TCP + API key instead):
./mcpproxy serve --enable-socket=falseSee docs/socket-communication.md for complete security model, implementation details, and testing info.
- Tool Discovery - BM25 search across all upstream MCP server tools
- Security Quarantine - Automatic quarantine of new servers to prevent Tool Poisoning Attacks
- Docker Security Isolation - Run stdio MCP servers in isolated Docker containers for enhanced security
- JavaScript Code Execution - Execute JavaScript to orchestrate multiple upstream tools in a single request, reducing latency and enabling complex workflows
- OAuth 2.1 Support - RFC 8252 compliant OAuth with PKCE for secure authentication
- System Tray UI - Native cross-platform tray interface for server management
- Per-Server Logging - Individual log files for each upstream server
- Real-time Event System - Event bus with SSE integration for live updates (Phase 3 refactoring)
- Hot Configuration Reload - Real-time config changes with event notifications
- Unix Socket/Named Pipe IPC - Secure local communication between tray and core without API keys (macOS/Linux: Unix sockets, Windows: Named pipes)
- Config:
~/.mcpproxy/mcp_config.json - Data:
~/.mcpproxy/config.db(BBolt database) - Index:
~/.mcpproxy/index.bleve/(search index) - Logs:
~/.mcpproxy/logs/(main.log + per-server logs)
{
"listen": "127.0.0.1:8080",
"data_dir": "~/.mcpproxy",
"api_key": "your-secret-api-key-here",
"enable_socket": true,
"enable_web_ui": true,
"top_k": 5,
"tools_limit": 15,
"tool_response_limit": 20000,
"mcpServers": [
{
"name": "github-server",
"url": "https://api.github.com/mcp",
"protocol": "http",
"enabled": true
},
{
"name": "ast-grep-project",
"command": "npx",
"args": ["ast-grep-mcp"],
"working_dir": "/home/user/projects/myproject",
"protocol": "stdio",
"env": { "API_KEY": "your-api-key" },
"enabled": true
}
]
}MCPProxy supports several environment variables for configuration and security:
Security Configuration:
MCPPROXY_LISTEN- Override network binding (e.g.,127.0.0.1:8080,:8080)MCPPROXY_API_KEY- Set API key for REST API authentication
Debugging:
MCPPROXY_DEBUG- Enable debug modeMCPPROXY_DISABLE_OAUTH- Disable OAuth for testingHEADLESS- Run in headless mode (no browser launching)
Tray-Core Communication:
MCPPROXY_API_KEY- Shared API key for tray-core authentication (auto-generated if not set)MCPPROXY_TLS_ENABLED- Enable TLS/HTTPS for both tray and core (automatically passed through)MCPPROXY_TRAY_SKIP_CORE- Skip core launch in tray app (for development)MCPPROXY_CORE_URL- Custom core URL for tray to connect to
Examples:
# Start with custom network binding
export MCPPROXY_LISTEN=":8080"
./mcpproxy serve
# Start with custom API key
export MCPPROXY_API_KEY="my-secret-key"
./mcpproxy serve
# Run in headless mode
export HEADLESS=true
./mcpproxy serveThe working_dir field specifies the working directory for stdio MCP servers. Useful for file-based servers (ast-grep-mcp, filesystem-mcp, git-mcp) to operate on your project directories instead of mcpproxy's directory.
- Empty/unspecified
working_diruses current directory (default behavior) - If directory doesn't exist, server startup fails with detailed error
- Compatible with Docker isolation (
isolation.working_dirfor container path)
MCPProxy supports arbitrary OAuth 2.0/2.1 extra parameters via the extra_params field in OAuth configuration. This enables integration with OAuth providers requiring non-standard parameters like RFC 8707 resource indicators.
Use Cases:
- RFC 8707 Resource Indicators: Specify target resource servers for multi-tenant authorization
- Audience-Restricted Tokens: Request tokens for specific API audiences
- Tenant Identification: Pass tenant/organization identifiers for multi-tenant OAuth
- Custom Provider Extensions: Support proprietary OAuth extensions from specific providers
Example 1: Runlayer MCP Server with Resource Parameter
{
"mcpServers": [
{
"name": "runlayer-slack",
"url": "https://oauth.runlayer.com/api/v1/proxy/abc123def/mcp",
"protocol": "http",
"enabled": true,
"oauth": {
"scopes": ["mcp"],
"pkce": true,
"extra_params": {
"resource": "https://oauth.runlayer.com/api/v1/proxy/abc123def/mcp"
}
}
}
]
}Example 2: Multi-Tenant OAuth with Multiple Parameters
{
"mcpServers": [
{
"name": "enterprise-mcp",
"url": "https://api.example.com/mcp",
"protocol": "http",
"enabled": true,
"oauth": {
"scopes": ["mcp:read", "mcp:write"],
"pkce": true,
"extra_params": {
"resource": "https://api.example.com/mcp",
"audience": "mcp-api",
"tenant": "org-456"
}
}
}
]
}Example 3: Azure AD with Resource Parameter
{
"mcpServers": [
{
"name": "azure-mcp",
"url": "https://mcp.azure.example.com/api",
"protocol": "http",
"enabled": true,
"oauth": {
"scopes": ["https://mcp.azure.example.com/.default"],
"pkce": true,
"authorization_url": "https://login.microsoftonline.com/tenant-id/oauth2/v2.0/authorize",
"token_url": "https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token",
"extra_params": {
"resource": "https://mcp.azure.example.com"
}
}
}
]
}Security & Validation:
- Reserved OAuth 2.0 parameters (
client_id,client_secret,redirect_uri,code,state,code_verifier,code_challenge,code_challenge_method) are rejected at config load time - Extra parameters are injected into all OAuth 2.0 requests: authorization, token exchange, and token refresh
- Parameter values containing secrets are automatically masked in logs (see
internal/oauth/masking.go)
Debugging OAuth Extra Parameters:
# View OAuth configuration including extra_params
mcpproxy auth status --server=runlayer-slack
# Test OAuth flow with debug logging
mcpproxy auth login --server=runlayer-slack --log-level=debug
# Check for OAuth-related issues
mcpproxy doctorImplementation Details:
- Uses HTTP
RoundTripperwrapper pattern (RFC 2616) for transparent request interception - Zero overhead for servers without
extra_paramsconfigured - Thread-safe concurrent OAuth flows with parameter isolation
- See
internal/oauth/transport_wrapper.gofor wrapper implementation
retrieve_tools- BM25 keyword search across all upstream toolscall_tool- Proxy tool calls to upstream serverscode_execution- Execute JavaScript to orchestrate multiple upstream tools (disabled by default)upstream_servers- CRUD operations for server management
- Format:
<serverName>:<originalToolName>(e.g.,github:create_issue) - Tools are automatically prefixed with server names to prevent conflicts
The HTTP API provides REST endpoints for server management and monitoring:
Base Path: /api/v1 (legacy /api routes removed in Phase 4)
Core Endpoints:
GET /api/v1/status- Server status and statisticsGET /api/v1/servers- List all upstream servers with connection statusPOST /api/v1/servers/{name}/enable- Enable/disable serverPOST /api/v1/servers/{name}/quarantine- Quarantine/unquarantine serverGET /api/v1/tools- Search tools across all serversGET /api/v1/servers/{name}/tools- List tools for specific server
Real-time Updates:
GET /events- Server-Sent Events (SSE) stream for live updates- Streams both status changes and runtime events (
servers.changed,config.reloaded) - Used by web UI and tray for real-time synchronization
API Authentication Examples:
# Using X-API-Key header (recommended for curl)
curl -H "X-API-Key: your-api-key" http://127.0.0.1:8080/api/v1/servers
# Using query parameter (for browser/SSE)
curl "http://127.0.0.1:8080/api/v1/servers?apikey=your-api-key"
# SSE with API key
curl "http://127.0.0.1:8080/events?apikey=your-api-key"
# Open Web UI with API key (tray app does this automatically)
open "http://127.0.0.1:8080/ui/?apikey=your-api-key"Security Notes:
- MCP endpoints (
/mcp,/mcp/) remain unprotected for client compatibility - REST API requires authentication - API key is always enforced (auto-generated if not provided)
- Secure by default: Empty or missing API keys trigger automatic generation and persistence to config
The code_execution tool enables orchestrating multiple upstream MCP tools in a single request using sandboxed JavaScript (ES5.1+).
{
"enable_code_execution": true,
"code_execution_timeout_ms": 120000,
"code_execution_max_tool_calls": 0,
"code_execution_pool_size": 10
}mcpproxy code exec --code="({ result: input.value * 2 })" --input='{"value": 21}'
mcpproxy code exec --code="call_tool('github', 'get_user', {username: input.user})" --input='{"user":"octocat"}'See docs/code_execution/ for complete guides:
overview.md- Architecture and best practicesexamples.md- 13 working code samplesapi-reference.md- Complete schema documentationtroubleshooting.md- Common issues and solutions
- Localhost-only binding by default: Core server binds to
127.0.0.1:8080by default to prevent network exposure - Override options: Can be changed via
--listenflag,MCPPROXY_LISTENenvironment variable, or config file - API key authentication: REST API endpoints protected with optional API key authentication
- MCP endpoints open: MCP protocol endpoints (
/mcp,/mcp/) remain unprotected for client compatibility
- Secure by default: API key is ALWAYS required - empty or missing keys trigger automatic generation
- Automatic generation: Auto-generated keys are saved to config file for persistence across restarts
- Multiple authentication methods: Supports
X-API-Keyheader and?apikey=query parameter - Tray integration: Tray app automatically generates and manages API keys for core communication
- Configuration priority:
MCPPROXY_API_KEYenv var > config fileapi_key> auto-generated - Protected endpoints:
/api/v1/*and/events(SSE) always require authentication - Unix socket bypass: Connections via Unix socket/named pipe (tray) bypass API key check (OS-level auth)
The tray application ensures secure communication with the core process through coordinated API key management:
- Environment Variable Priority: If
MCPPROXY_API_KEYis set, both tray and core use the same key - Auto-Generation: If no API key is provided, tray generates one and passes it to core via environment
- Core Process Environment: Tray always passes
MCPPROXY_API_KEYto the core process it launches - TLS Configuration: When
MCPPROXY_TLS_ENABLED=true, it's automatically passed to the core process
This prevents the "API key auto-generated for security" mismatch that would prevent tray-core communication.
- All new servers added via LLM tools are automatically quarantined
- Quarantined servers cannot execute tools until manually approved
- Tool calls to quarantined servers return security analysis instead of executing
- Approval requires manual action via system tray or config file editing
- Automatic detection of malicious tool descriptions
- Security analysis with comprehensive checklists
- Protection against hidden instructions and data exfiltration attempts
The core mcpproxy process uses specific exit codes to communicate failure reasons to the tray application:
Exit Codes (cmd/mcpproxy/exit_codes.go):
0- Success (normal termination)1- General error (default for unclassified errors)2- Port conflict (listen address already in use)3- Database locked (another mcpproxy instance running)4- Configuration error (invalid config file)5- Permission error (insufficient file/port access)
Tray Integration:
The tray application's process monitor (cmd/mcpproxy-tray/internal/monitor/process.go) maps these exit codes to state machine events, enabling intelligent retry strategies and user-friendly error reporting.
Run this first when debugging any issue:
mcpproxy doctorThis checks for:
- Upstream server connection errors
- OAuth authentication requirements
- Missing secrets
- Runtime warnings
- Docker isolation status
See docs/cli-management-commands.md for detailed workflows.
# Monitor logs
tail -f ~/Library/Logs/mcpproxy/main.log
# Check server status
mcpproxy upstream list
# View specific server logs
mcpproxy upstream logs github-server --tail=100
# Follow logs in real-time (requires daemon)
mcpproxy upstream logs github-server --follow
# Restart problematic server
mcpproxy upstream restart github-server
# Filter for errors
tail -f ~/Library/Logs/mcpproxy/main.log | grep -E "(ERROR|WARN)"
# Debug mode
pkill mcpproxy && ./mcpproxy serve --log-level=debug
# OAuth debugging
mcpproxy auth login --server=Sentry --log-level=debug- Main log:
~/Library/Logs/mcpproxy/main.log(macOS) or~/.mcpproxy/logs/main.log(Linux/Windows) - Per-server logs:
~/Library/Logs/mcpproxy/server-{name}.log
- Use the existing modular architecture with clear separation of concerns
- Place new features in appropriate
internal/subdirectories - Follow Go package naming conventions
- Unit tests alongside source files (
*_test.go) - E2E tests in
internal/server/e2e_test.go - Use testify for assertions and mocking
- Test files should be comprehensive and test both success and error cases
- Use structured logging with zap
- Wrap errors with context using
fmt.Errorf - Handle context cancellation properly in long-running operations
- Graceful degradation for non-critical failures
- Config changes should update both storage and file system
- File watcher triggers automatic config reloads
- Validate configuration on load and provide sensible defaults
The runtime package provides the core non-HTTP lifecycle management, separating concerns from the HTTP server layer:
- Configuration Management: Centralized config loading, validation, and hot-reload
- Background Services: Connection management, tool indexing, and health monitoring
- State Management: Thread-safe status tracking and upstream server state
- Event System: Real-time event broadcasting for UI and SSE consumers
The event bus enables real-time communication between runtime and UI components:
Event Types:
servers.changed- Server configuration or state changesconfig.reloaded- Configuration file reloaded from disk
Event Flow:
- Runtime operations trigger events via
emitServersChanged()andemitConfigReloaded() - Events are broadcast to subscribers through buffered channels
- Server forwards events to tray UI and SSE endpoints
- Tray menus refresh automatically without file watching
- Web UI receives live updates via
/eventsSSE endpoint
SSE Integration:
/eventsendpoint streams both status updates and runtime events- Automatic connection management with proper cleanup
- JSON-formatted event payloads for easy consumption
Initialization:
- Runtime created with config, logger, and manager dependencies
- Background initialization starts server connections and tool indexing
- Status updates broadcast through event system
Background Services:
- Connection Management: Periodic reconnection attempts with exponential backoff
- Tool Indexing: Automatic discovery and search index updates every 15 minutes
- Configuration Sync: File-based config changes trigger runtime resync
Shutdown:
- Graceful context cancellation cascades to all background services
- Upstream servers disconnected with proper Docker container cleanup
- Resources closed in dependency order (upstream → cache → index → storage)
- Runtime Detection: Automatically detects command type (uvx→Python, npx→Node.js, etc.)
- Image Selection: Maps to appropriate Docker images with required tools and Git support
- Environment Passing: API keys and config securely passed via
-eflags - Container Lifecycle: Proper cleanup with cidfile tracking and health monitoring
- Conflict Avoidance: Skips isolation for existing Docker commands to prevent nested containers
- Resource Limits: Memory and CPU limits prevent resource exhaustion
- Full Image Support: Uses
python:3.11andnode:20(not slim/alpine) for Git and build tools
- Uses dynamic port allocation for callback servers
- RFC 8252 compliant with PKCE for security
- Automatic browser launching for authentication flows
- Global callback server manager prevents port conflicts
- OAuth Flow Coordinator (
internal/oauth/coordinator.go): Prevents race conditions with per-server OAuth flow coordination - Token Refresh: Automatic token refresh using refresh_token before browser re-authentication
- Correlation IDs: UUID-based tracing for all OAuth operations (
internal/oauth/correlation.go) - Token Redaction: Sensitive data automatically redacted in logs (
internal/oauth/logging.go)
- Background connection attempts with exponential backoff
- Separate contexts for application vs server lifecycle
- Connection state machine: Disconnected → Connecting → Authenticating → Ready
- Full rebuild on server changes
- Hash-based change detection to skip unchanged tools
- Background indexing doesn't block server operations
- Main application log:
main.log - Per-server logs:
server-{name}.log - Docker container logs automatically captured and integrated
- Automatic log rotation and compression
- Configurable log levels and output formats
- Graceful shutdown with proper resource cleanup
- Context cancellation for background operations
- HTTP server shutdown with timeout
- Docker container cleanup on shutdown
- Double shutdown protection
When making changes to this codebase, ensure you understand the modular architecture and maintain the clear separation between core protocol handling, state management, and user interface components.
- remember before running mcpproxy core u need to kill all mcpproxy instances, because it locks DB
- Go 1.21+, TypeScript/Vue 3 (003-tool-annotations-webui)
- BBolt (existing
server_{serverID}_tool_callsbuckets, newsessionsbucket) (003-tool-annotations-webui) - Go 1.24.0 (004-management-health-refactor)
- BBolt embedded database (
~/.mcpproxy/config.db) for server configurations, quarantine status, and tool statistics (004-management-health-refactor) - BBolt embedded database (
~/.mcpproxy/config.db) - used by existing runtime, no changes required (005-rest-management-integration) - N/A (documentation-only feature) (001-oas-endpoint-documentation)
- BBolt embedded database (
~/.mcpproxy/config.db) - used by existing runtime for server configurations and OAuth token persistence, no schema changes required (006-oauth-extra-params) - Go 1.24.0 (as per existing project) (007-oauth-e2e-testing)
- BBolt (existing
internal/storage/) for token persistence (007-oauth-e2e-testing) - Go 1.24.0 + mcp-go (OAuth transport), zap (logging), BBolt (token persistence), google/uuid (correlation IDs) (008-oauth-token-refresh)
- BBolt embedded database (
~/.mcpproxy/config.db) -oauth_tokensandoauth_completionbuckets (008-oauth-token-refresh)
- 003-tool-annotations-webui: Added Go 1.21+, TypeScript/Vue 3
