This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
MCP Server Manager is a Go web application that centralizes management of Model Context Protocol (MCP) servers across multiple AI clients. It solves the problem of manually editing various JSON files for different MCP clients by providing a single YAML configuration file and web interface.
Key Features:
- Single binary with embedded assets (no external dependencies)
- Cross-platform support (Linux, macOS, Windows)
- Real-time web interface with HTMX
- Dark/light theme system with manual override and system preference detection
- Automatic client config synchronization
- Server order preservation in UI and configuration
- Systemd integration for auto-start
- DO NOT run
make run- The development server is already running in the background - DO NOT include Claude Code attribution in git commits - Use semantic commit messages instead
- Use semantic git commit format:
feat:,fix:,docs:,refactor:,chore:, etc. - Example:
feat: add syntax highlighting to config viewerinstead of generic attribution - After completing a task, ask for confirmation then check it in the TODO list below and suggest the commit message
make build- Build the binary tobin/mcp-server-manager(single binary with embedded assets)make test- Run all Go testsmake test-coverage- Run tests with coverage report (generatescoverage.outfor SonarQube)make install-deps- Download and organize Go dependenciesmake setup- Complete production setup (build, install systemd user service, enable, start)make logs-service- View systemd user service logs in real-timemake status-service- Check systemd user service statusmake sync-assets- Sync web assets from web/ to internal/assets/web/ for embeddingmake test-release- Build local .deb package, install, and restart service for testingmake release VERSION=x.x.x- Create git tag and trigger GitHub Actions releasemake clean- Remove build artifacts and coverage files
make test-release- Build and test .deb package locally before releasemake release VERSION=v1.1.0- Create official release with git tag and trigger GitHub Actionsmake release VERSION=v1.1.0 MESSAGE="Custom release summary"- Create release with custom messagemake sync-assets- Sync web assets to embedded location (auto-included in build/release)- This triggers GitHub Actions to build cross-platform binaries via GoReleaser
- Produces releases for Linux, macOS, Windows (amd64 + arm64)
When asked to create a release, Claude should:
- Analyze commits since the last git tag to understand changes - IMPORTANT: Use
git log --format="%H%n%s%n%b%n---"to read full commit bodies (not just one-line summaries) - Create a fun, engaging release summary in the style of YNAB release notes - casual, slightly humorous, user-focused
- Summarize features/improvements in a non-technical way that users would understand and appreciate
- Format the message with a subject line, blank line, and body for proper GoReleaser parsing
- IMPORTANT: To avoid shell quoting issues, write the message to
/tmp/release_message.txtand use git tag directly
Message Format Requirements:
- First line: Short, catchy subject (will appear as release title)
- Second line: Must be blank
- Remaining lines: Detailed description with features, improvements, etc.
Recommended approach (avoids quoting issues):
# Write message to temp file
cat > /tmp/release_message.txt << 'EOF'
Fresh updates for your MCP setup! 🎉
We've been busy little bees! 🐝 This release brings you a shiny new dark mode (because your eyes deserve better at 2 AM), smoother animations that'll make you smile, and we finally ditched that confusing global toggle that nobody understood anyway. Your MCP servers have never looked so good!
EOF
# Create and push release tag
make test && make sync-assets && git tag -a v1.4.0 -F /tmp/release_message.txt && git push origin v1.4.0Alternative (if MESSAGE parameter works):
make release VERSION=v1.4.0 MESSAGE="Subject line
Body content..."- Project maintains 64.8% overall test coverage
- Coverage tracking configured for SonarQube CI-based analysis
- Run
make test-coverageto generate coverage reports locally - Coverage file:
coverage.out(auto-generated in CI, not committed) - View coverage:
go tool cover -func=coverage.outorgo tool cover -html=coverage.out
- Analysis Type: CI-based analysis via GitHub Actions (
.github/workflows/sonarqube.yml) - Configuration:
sonar-project.properties - Coverage Reporting: Automatic via GitHub Actions workflow
- Tests run with coverage:
go test -coverprofile=coverage.out ./... - Coverage data sent to SonarQube Cloud on every push/PR
- Tests run with coverage:
- Strategic exclusions configured:
- Test file naming conventions (Go uses underscores)
- Intentional code duplication (web/ ↔ internal/assets/web/)
- Test-specific cognitive complexity rules
- Graceful error handling patterns
- Quality Gate: PASSED ✓
- Setup Requirements:
SONAR_TOKENsecret in GitHub (set via:gh secret set SONAR_TOKEN)- Automatic analysis disabled in SonarQube Cloud UI
Why CI-based Analysis?:
- SonarQube automatic analysis (GitHub App) doesn't support coverage reporting
- CI-based analysis generates coverage.out during the workflow run
- Coverage data is sent directly to SonarQube from the CI environment
- GitHub App still provides PR decoration and other features
Project Information (use these directly to skip search):
- Project Key:
vlazic_mcp-server-manager - Project Name:
mcp-server-manager - Organization:
vlazic
Efficient MCP Tool Usage:
# Get quality gate status directly (no search needed)
get_project_quality_gate_status(projectKey: "vlazic_mcp-server-manager")
# Search issues in this project
search_sonar_issues_in_projects(projects: ["vlazic_mcp-server-manager"], ps: 50)
# Get specific metrics
get_component_measures(component: "vlazic_mcp-server-manager", metricKeys: [...])
Performance Tips:
- Skip
search_my_sonarqube_projects- use project key directly - Large issue responses (~10k tokens for 100 issues) - use pagination (
ps: 50) or filter by severity - Check quality gate first to identify specific failing conditions
- Use
get_component_measuresfor targeted metric analysis instead of full issue list
├── cmd/server/main.go # Application entry point with embedded assets setup
├── internal/
│ ├── assets/ # Embedded web assets (templates, CSS, JS)
│ │ └── web/ # Mirror of web/ directory for embedding
│ ├── config/loader.go # YAML config loading/saving with order preservation
│ ├── handlers/ # HTTP request handlers
│ │ ├── api.go # REST API endpoints for programmatic access
│ │ ├── web.go # HTMX endpoints returning HTML fragments
│ │ └── config_viewer.go # Configuration display handlers
│ ├── models/config.go # Data structures: MCPServer (ordered slice), Client
│ └── services/ # Core business logic
│ ├── mcp_manager.go # Central orchestration service
│ ├── client_config.go # Client JSON config manipulation
│ └── validator.go # Configuration validation logic
├── web/ # Source templates and static files
│ ├── templates/*.html # Go templates with HTMX integration
│ └── static/ # CSS, JS, Prism.js syntax highlighting
├── configs/config.yaml # Example configuration file
└── systemd/mcp-server-manager.service # User systemd service definition
MCPManagerService (internal/services/mcp_manager.go):
- Central orchestrator coordinating between central config and client configs
- Handles per-client server toggling (no global toggle - simplified in v2.0)
- Manages the two-layer configuration model (central YAML → client JSONs)
- Preserves server order from YAML configuration
ClientConfigService (internal/services/client_config.go):
- Reads/writes individual AI client configuration files
- Handles heterogeneous client config formats (Claude vs Gemini structures)
- Creates automatic timestamped backups before modifications
- Preserves existing client settings (theme, auth, etc.) during updates
ValidatorService (internal/services/validator.go):
- Validates YAML configuration and client JSON structures
- Checks command availability in PATH for MCP servers
- Handles different server types (command-based vs HTTP-based)
The application operates on a two-layer configuration model:
-
Central Configuration (
configs/config.yaml):- Map-based YAML format for easy editing (mcpServers as key-value pairs)
- Defines all available MCP servers with commands, args, environment variables
- Specifies which clients exist and their config file paths
- Controls per-client server enable/disable states (array of enabled server names)
- Server order preserved using yaml.v3 Node parsing (v2.0+)
-
Client Configurations (e.g.,
~/.claude.json,~/.gemini/settings.json):- Individual AI client settings that get automatically updated
- Preserves client-specific settings (themes, auth) while updating MCP sections
- Supports different formats: Claude (command-based) vs Gemini (command + HTTP)
Internal Representation (v2.0+):
- YAML map is parsed and converted to ordered slice:
[]MCPServer{Name, Config} - Preserves order from YAML file using yaml.v3 Node traversal
- UI displays servers in the same order as defined in config file
Handler Types:
- APIHandler: REST endpoints (
/api/*) for programmatic access, returns JSON - WebHandler: HTMX endpoints (
/htmx/*) returning HTML fragments for reactive UI - ConfigViewerHandler: Read-only configuration display with syntax highlighting
HTMX Integration Patterns:
- Toggle checkboxes post to
/htmx/...endpoints, update specific DOM elements - Config viewers use
hx-trigger="revealed, configChanged from:body"for lazy loading + auto-refresh - Custom
configChangedevents trigger config viewer refreshes after any changes - Hyperscript handles event triggering after HTMX requests complete
Add New Servers via Web UI:
- Form-based server addition with JSON validation
- Real-time validation for MCP client configuration format
- Example configurations for STDIO, HTTP, SSE, and Context7 servers
- Client-side validation before submission
- Form positioned below button with slide animation
Interactive Configuration Examples:
- Pre-built examples for common server types
- One-click loading of example configurations
- Supports all transport types (command, httpUrl, url)
Configuration Display:
- YAML config displayed in original format (not JSON conversion)
- Real-time syntax highlighting with Prism.js
- Auto-refresh after configuration changes
Dark/Light Theme System (v1.3.0+):
- System theme detection as default
- Manual theme override (light/dark/system)
- Theme preference persisted in localStorage
- Immediate theme application to prevent flash on page load
- CSS custom properties for consistent theming across all components
Production Build:
- Uses
//go:embedto bundle all web assets into the binary internal/assets/assets.godefines embedded filesystems for templates and static files- No external file dependencies in production - completely self-contained binary
- Template parsing uses
template.ParseFS()with customdictfunction for HTMX data passing
Development vs Production:
- Development: Templates loaded from
web/templates/, static files fromweb/static/ - Production: Everything embedded, served from memory via
http.FS() - Asset sync: Changes in
web/must be copied tointernal/assets/web/for embedding
Heterogeneous Config Formats:
- Claude:
mcpServerswith command/args structure - Gemini:
mcpServerssupporting both command-based AND HTTP servers with headers - Solution:
MCPServer.Configusesmap[string]interface{}for flexibility (v2.0+) - All fields from central config passed through to clients (no filtering)
Synchronization Process:
- Read current client config (create empty if missing)
- Update
mcpServerssection based on central config + client-specific overrides - Preserve non-MCP settings (authentication, themes, editor preferences)
- Create automatic
.backup.TIMESTAMPfiles before writing - Validate structure before writing to prevent corruption
Data Model (v2.0+):
type MCPServer struct {
Name string // Server identifier
Config map[string]interface{} // Flexible config (command, args, env, type, url, etc.)
}
type Client struct {
ConfigPath string // Path to client JSON config
Enabled []string // List of enabled server names
}Development Environment:
- Server runs on port 6543
- Development server runs in background - never run
make runduring development - Changes to templates/static files require
make sync-assetsor are auto-synced during build - Use
make test-releaseto test complete .deb package installation locally
Code Quality & Simplification:
- v2.0 refactoring removed 880 lines of code while adding functionality
- Simplified architecture: removed global enable/disable complexity
- Better order preservation with yaml.v3 Node parsing
- More robust client config handling preserves all fields
Git Workflow:
- Use semantic commit messages:
feat:,fix:,docs:,refactor:,chore: - Never include Claude Code attribution in commits
- Example:
feat: add syntax highlighting to config viewer
Production Deployment:
- Single binary with embedded assets (no external dependencies)
- Cross-platform releases via GoReleaser (Linux/macOS/Windows, amd64/arm64)
- Systemd user service integration for Linux auto-start
- Release triggered by Git tag push, builds via GitHub Actions
Prism.js Integration:
- Embedded Prism.js core, YAML, and JSON language modules
- Config viewers automatically detect content type (JSON for client configs)
- HTMX auto-refresh triggers
Prism.highlightAllUnder()for new content - CSS and JS files embedded in binary via assets system
- Remove MCP servers via Web UI
- Test on macOS and Windows
- Allow users to edit files in the Web UI
- When the app config is changed manually on disk, the web UI does not reflect the changes until the server is restarted.
- Investigate and document the requirement for enabling user lingering (
loginctl enable-linger <username>) to ensure the systemd user service starts automatically on system boot. - Add 'profiles' functionality (low priority) to save and restore different application configurations. This would allow users to switch between predefined sets of server states. Implementation could involve a new
profileskey in the main config file or a small local database. - Refactor the 'Add New Server' functionality. The current implementation uses a full page reload, which prevents the success notification from being displayed. Change it to use HTMX to asynchronously add the server and update the server list in place, without a page reload. This will also allow the success notification to be displayed correctly.
- Allow adding new clients and their config paths via the web UI. As part of this, consider refactoring the
clientssection in the main config from a map to an array of objects (e.g.,{name: 'client-name', path: '/path/to/config.json'}) for easier manipulation. - Investigate adding a feature to open configuration files in the user's default text editor directly from the web UI.
- Update the documentation to explain the benefits of using a dotfile manager (e.g.,
chezmoi) to manage the centralconfig.yaml. Mention that this allows for version control, synchronization, and managing secrets like API keys through the dotfile manager's encryption features. https://www.chezmoi.io/ - Consider removing the 'global' enable/disable flag for servers. It adds complexity, may be buggy, and per-client toggles may be sufficient, which would simplify the UI and configuration logic.
- Move the input field for adding a new server to be below the button and above the list of servers.
- Implement a dark theme, which defaults to the system theme and allows for manual override.