Skip to content

Commit 56f6863

Browse files
authored
feature/servers logs (#10)
* Enhance logging system and add tail_log operation - Updated logging configuration to support custom log directories and filenames. - Introduced `tail_log` operation for reading recent log entries from upstream servers, aiding in debugging. - Improved log structure and content for better traceability of MCP server interactions. - Adjusted CLI commands and documentation to reflect new logging features and configurations. * Add GetLogDir method to ServerInterface and implement log directory handling - Introduced GetLogDir method in ServerInterface for retrieving the log directory path. - Implemented GetLogDir in Server to return configured log directory or default paths. - Updated tray application to include functionality for opening the logs directory. - Enhanced error handling and logging for directory access operations. * Update log file references from 'mcpproxy.log' to 'main.log' across workflows and internal logging configurations * Update README and workflow documentation for system tray flag usage; clarify command-line options for enabling/disabling system tray functionality. * Refactor logging levels in logger.go to use constants for improved readability and maintainability
1 parent 7969ff6 commit 56f6863

17 files changed

Lines changed: 451 additions & 56 deletions

File tree

.github/workflows/e2e-tests.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ jobs:
118118
119119
# Verify log file was created in standard OS location
120120
if [ "$(uname)" = "Linux" ]; then
121-
if [ -f "$HOME/.local/state/mcpproxy/logs/mcpproxy.log" ]; then
121+
if [ -f "$HOME/.local/state/mcpproxy/logs/main.log" ]; then
122122
echo "✓ Log file created in Linux standard location"
123-
head -5 "$HOME/.local/state/mcpproxy/logs/mcpproxy.log"
123+
head -5 "$HOME/.local/state/mcpproxy/logs/main.log"
124124
else
125125
echo "⚠ Log file not found in expected location"
126126
fi
@@ -219,20 +219,20 @@ jobs:
219219
ls -la "${{ matrix.log_path_check }}"
220220
221221
# Check if log file exists and has content
222-
if [ -f "${{ matrix.log_path_check }}/mcpproxy.log" ]; then
222+
if [ -f "${{ matrix.log_path_check }}/main.log" ]; then
223223
echo "✓ Log file created successfully"
224-
echo "Log file size: $(wc -c < "${{ matrix.log_path_check }}/mcpproxy.log") bytes"
224+
echo "Log file size: $(wc -c < "${{ matrix.log_path_check }}/main.log") bytes"
225225
echo "First few lines:"
226-
head -3 "${{ matrix.log_path_check }}/mcpproxy.log"
226+
head -3 "${{ matrix.log_path_check }}/main.log"
227227
228228
# Verify log contains expected content
229-
if grep -q "Log directory configured" "${{ matrix.log_path_check }}/mcpproxy.log"; then
229+
if grep -q "Log directory configured" "${{ matrix.log_path_check }}/main.log"; then
230230
echo "✓ Log contains expected startup messages"
231231
else
232232
echo "⚠ Log missing expected startup messages"
233233
fi
234234
235-
if grep -q "${{ matrix.log_standard }}" "${{ matrix.log_path_check }}/mcpproxy.log"; then
235+
if grep -q "${{ matrix.log_standard }}" "${{ matrix.log_path_check }}/main.log"; then
236236
echo "✓ Log contains OS standard compliance information"
237237
else
238238
echo "⚠ Log missing OS standard compliance information"
@@ -274,7 +274,7 @@ jobs:
274274
Get-ChildItem $logPath
275275
276276
# Check if log file exists and has content
277-
$logFile = Join-Path $logPath "mcpproxy.log"
277+
$logFile = Join-Path $logPath "main.log"
278278
if (-not (Test-Path $logFile)) {
279279
Write-Host "✗ Log file not created"
280280
exit 1

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ jobs:
549549
550550
- With tray: `./mcpproxy` (default)
551551
- Custom port (default: 8080): `./mcpproxy --listen :8081`
552-
- Headless: `./mcpproxy --tray false`
552+
- Headless: `./mcpproxy --tray=false`
553553
env:
554554
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
555555

DESIGN.md

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ Re‑implement the existing Python MCP proxy in Go, delivering a single‑binary
2424

2525
* WebSocket/stdin transports, distributed indexing, vector search.
2626

27-
## 3  Tech Stack
27+
## 3  Tech Stack
2828

2929
| Concern | Library | Reason |
3030
| ----------------- | --------------------------------- | ---------------------------------- |
3131
| MCP server/client | **`mark3labs/mcp-go`** | Native Go, Streamable‑HTTP support |
32-
| Full‑text search | **Bleve v2** | Embeddable BM25 |
32+
| Full‑text search | **Bleve v2** | Embeddable BM25 |
3333
| CLI & config | **`spf13/cobra` + `spf13/viper`** | Flags → env → file binding |
3434
| Persistence | **bbolt** | Single‑file ACID |
3535
| Sys‑tray | **`fyne.io/systray`** | Tiny cross‑platform tray |
@@ -66,7 +66,7 @@ Re‑implement the existing Python MCP proxy in Go, delivering a single‑binary
6666
* Stored alongside tool metadata in both Bleve doc and Bolt `toolhash` bucket.
6767
* During re‑sync `ListTools` results are hashed; unchanged hashes skip re‑indexing.
6868

69-
## 6  Data Model (bbolt)
69+
## 6  Data Model (bbolt)
7070

7171
| Bucket | Key | Value |
7272
| ----------- | ------------- | ---------------------------- |
@@ -119,7 +119,22 @@ Input: {"operation":"add","url":"https://api.mcp.dev","name":"dev"}
119119
Output: {"id":"uuid","enabled":true}
120120
```
121121

122-
Operations: `list` / `add` / `remove` / `update`.
122+
Operations: `list` / `add` / `remove` / `update` / `tail_log`.
123+
124+
#### 8.3.1 `tail_log` Operation
125+
126+
The `tail_log` operation allows LLMs to read recent log entries from a specific upstream server for debugging purposes:
127+
128+
```jsonc
129+
Input: {"operation":"tail_log","name":"dev","lines":50}
130+
Output: {"server":"dev","lines":50,"log_entries":[...]}
131+
```
132+
133+
**Parameters:**
134+
- `name` (required): Server name to read logs from
135+
- `lines` (optional): Number of recent lines to return (default: 50, max: 500)
136+
137+
**Use Case:** Enables AI agents to autonomously diagnose connection issues, authentication failures, and other upstream server problems by reading recent log entries.
123138

124139
### 8.4  `tools_stat`
125140

@@ -134,10 +149,55 @@ Returns `{total_tools, top:[{tool_name,count}]}`.
134149

135150
## 10  CLI, Config & Tray
136151

137-
* `mcpproxy [--listen :8080] [--data-dir ~/.mcpproxy] [--upstream "prod=https://api"]`
152+
* `mcpproxy [--listen :8080] [--log-dir ~/.mcpproxy/logs] [--upstream "prod=https://api"]`
138153
* Viper reads `$MCPP_` envs and `config.toml`.
139154
* Tray (systray): icon + menu items (Enable, Disable, Add…, Reindex, Quit).
140155

156+
### 10.1 Logging System
157+
158+
#### Per-Upstream Server Logging
159+
160+
mcpproxy implements comprehensive per-upstream-server logging to facilitate debugging of connection issues and MCP communication problems.
161+
162+
**Log File Structure:**
163+
```
164+
~/.mcpproxy/logs/
165+
├── main.log # Main application log
166+
├── server-github.log # GitHub MCP server interactions
167+
├── server-filesystem.log # Filesystem MCP server interactions
168+
└── server-database.log # Database MCP server interactions
169+
```
170+
171+
**Log Content:**
172+
- **MCP Protocol Messages**: All JSON-RPC messages between mcpproxy and upstream servers
173+
- **Connection Events**: Connect, disconnect, retry attempts, and failures
174+
- **Authentication**: OAuth flows, token refreshes, and auth errors
175+
- **Process Output**: STDERR from stdio-based MCP servers
176+
- **Timing Information**: Request/response latencies and timeout events
177+
178+
**Example Log Format:**
179+
```
180+
2025-06-04T03:42:38.375Z [github] [info] Connecting to upstream server
181+
2025-06-04T03:42:38.630Z [github] [info] Connected successfully
182+
2025-06-04T03:42:38.663Z [github] [debug] [Client→Server] initialize
183+
2025-06-04T03:42:38.663Z [github] [debug] {"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"mcpproxy-go","version":"1.0.0"}},"jsonrpc":"2.0","id":0}
184+
2025-06-04T03:42:38.700Z [github] [debug] [Server→Client] 0
185+
2025-06-04T03:42:38.700Z [github] [debug] {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":false}},"serverInfo":{"name":"GitHub MCP Server","version":"1.0.0"}}}
186+
2025-06-04T03:42:41.670Z [github] [error] Connection error: HTTP 500 - Internal Server Error
187+
2025-06-04T03:42:41.671Z [github] [info] Attempting reconnection in 5 seconds...
188+
```
189+
190+
**CLI Configuration:**
191+
- `--log-dir`: Specify custom log directory (default: OS-specific standard location)
192+
- `--log-level`: Set log level for all loggers (debug, info, warn, error)
193+
- Main application log: `main.log`
194+
- Per-server logs: `server-{name}.log`
195+
196+
**Log Rotation:**
197+
- Automatic rotation based on file size (10MB default)
198+
- Configurable retention (5 backup files, 30 days default)
199+
- Optional compression for rotated files
200+
141201
## 11  Build & Packaging
142202

143203
* Cross‑compile via `GOOS=darwin/windows/linux`.
@@ -171,7 +231,10 @@ The proxy supports dynamic management of upstream MCP servers through the `upstr
171231
~/.mcpproxy/
172232
├── mcp_config.json # Main configuration file
173233
├── data.bolt # BoltDB storage (tool stats, metadata)
174-
└── index.bleve/ # Search index directory
234+
├── index.bleve/ # Search index directory
235+
└── logs/ # Log files directory
236+
├── main.log # Main application log
237+
└── server-*.log # Per-upstream server logs
175238
```
176239

177240
#### Configuration Flow

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ mcpproxy --help
116116
-c, --config <file> path to mcp_config.json
117117
-l, --listen <addr> listen address (":8080")
118118
-d, --data-dir <dir> custom data directory
119-
--tray enable/disable system tray (default true)
119+
--tray enable/disable system tray (default true, use --tray=false to disable)
120120
--log-level <level> debug|info|warn|error
121121
--read-only forbid config changes
122122
--disable-management disable upstream_servers tool

cmd/mcpproxy/main.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ var (
2525
debugSearch bool
2626
toolResponseLimit int
2727
logToFile bool
28-
logFile string
28+
logDir string
2929

3030
// Security flags
3131
readOnlyMode bool
@@ -57,11 +57,11 @@ func main() {
5757
rootCmd.PersistentFlags().StringVarP(&dataDir, "data-dir", "d", "", "Data directory path (default: ~/.mcpproxy)")
5858
rootCmd.PersistentFlags().StringVarP(&listen, "listen", "l", "", "Listen address (for HTTP mode, not used in stdio mode)")
5959
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error)")
60-
rootCmd.PersistentFlags().BoolVar(&enableTray, "tray", true, "Enable system tray")
60+
rootCmd.PersistentFlags().BoolVar(&enableTray, "tray", true, "Enable system tray (use --tray=false to disable)")
6161
rootCmd.PersistentFlags().BoolVar(&debugSearch, "debug-search", false, "Enable debug search tool for search relevancy debugging")
6262
rootCmd.PersistentFlags().IntVar(&toolResponseLimit, "tool-response-limit", 0, "Tool response limit in characters (0 = disabled, default: 20000 from config)")
6363
rootCmd.PersistentFlags().BoolVar(&logToFile, "log-to-file", true, "Enable logging to file in standard OS location")
64-
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", "", "Custom log file path (overrides standard OS location)")
64+
rootCmd.PersistentFlags().StringVar(&logDir, "log-dir", "", "Custom log directory path (overrides standard OS location)")
6565
rootCmd.PersistentFlags().BoolVar(&readOnlyMode, "read-only", false, "Enable read-only mode")
6666
rootCmd.PersistentFlags().BoolVar(&disableManagement, "disable-management", false, "Disable management features")
6767
rootCmd.PersistentFlags().BoolVar(&allowServerAdd, "allow-server-add", true, "Allow adding new servers")
@@ -74,7 +74,7 @@ func main() {
7474
}
7575
}
7676

77-
func runServer(_ *cobra.Command, _ []string) error {
77+
func runServer(cmd *cobra.Command, _ []string) error {
7878
// Load configuration first to get logging settings
7979
cfg, err := loadConfig()
8080
if err != nil {
@@ -87,7 +87,7 @@ func runServer(_ *cobra.Command, _ []string) error {
8787
Level: logLevel,
8888
EnableFile: logToFile,
8989
EnableConsole: true,
90-
Filename: "mcpproxy.log",
90+
Filename: "main.log",
9191
MaxSize: 10,
9292
MaxBackups: 5,
9393
MaxAge: 30,
@@ -98,11 +98,16 @@ func runServer(_ *cobra.Command, _ []string) error {
9898
// Override specific fields from command line
9999
cfg.Logging.Level = logLevel
100100
cfg.Logging.EnableFile = logToFile
101-
if logFile != "" {
102-
cfg.Logging.Filename = logFile
101+
if cfg.Logging.Filename == "" || cfg.Logging.Filename == "mcpproxy.log" {
102+
cfg.Logging.Filename = "main.log"
103103
}
104104
}
105105

106+
// Override log directory if specified
107+
if logDir != "" {
108+
cfg.Logging.LogDir = logDir
109+
}
110+
106111
// Setup logger with new logging system
107112
logger, err := logs.SetupLogger(cfg.Logging)
108113
if err != nil {
@@ -130,7 +135,10 @@ func runServer(_ *cobra.Command, _ []string) error {
130135
zap.Bool("log_to_file", logToFile))
131136

132137
// Override other settings from command line
133-
cfg.EnableTray = enableTray
138+
// Check if the tray flag was explicitly set by the user
139+
if cmd.Flags().Changed("tray") {
140+
cfg.EnableTray = enableTray
141+
}
134142
cfg.DebugSearch = debugSearch
135143

136144
if toolResponseLimit != 0 {

internal/config/config.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ type LogConfig struct {
3939
EnableFile bool `json:"enable_file" mapstructure:"enable-file"`
4040
EnableConsole bool `json:"enable_console" mapstructure:"enable-console"`
4141
Filename string `json:"filename" mapstructure:"filename"`
42-
MaxSize int `json:"max_size" mapstructure:"max-size"` // MB
43-
MaxBackups int `json:"max_backups" mapstructure:"max-backups"` // number of backup files
44-
MaxAge int `json:"max_age" mapstructure:"max-age"` // days
42+
LogDir string `json:"log_dir,omitempty" mapstructure:"log-dir"` // Custom log directory
43+
MaxSize int `json:"max_size" mapstructure:"max-size"` // MB
44+
MaxBackups int `json:"max_backups" mapstructure:"max-backups"` // number of backup files
45+
MaxAge int `json:"max_age" mapstructure:"max-age"` // days
4546
Compress bool `json:"compress" mapstructure:"compress"`
4647
JSONFormat bool `json:"json_format" mapstructure:"json-format"`
4748
}
@@ -158,7 +159,7 @@ func DefaultConfig() *Config {
158159
Level: "info",
159160
EnableFile: true,
160161
EnableConsole: true,
161-
Filename: "mcpproxy.log",
162+
Filename: "main.log",
162163
MaxSize: 10, // 10MB
163164
MaxBackups: 5, // 5 backup files
164165
MaxAge: 30, // 30 days

internal/config/loader.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ func setupViper() {
139139

140140
// Set defaults
141141
viper.SetDefault("listen", ":8080")
142-
viper.SetDefault("tray", true)
143142
viper.SetDefault("top-k", 5)
144143
viper.SetDefault("tools-limit", 15)
145144
viper.SetDefault("config", "")

0 commit comments

Comments
 (0)